/**
 * 构造器和函数的区别是，构造器是用于创建对象的，所以可以被 new。
 *
 * 同样，我们也可以通过模式匹配提取构造器的参数和返回值的类型：
 *
 * GetInstanceType
 *
 * 构造器类型可以用 interface 声明，使用 new(): xx 的语法。
 */

interface Person {
  name: string;
}

interface PersonConstructor {
  new (name: string): Person;
}

type GetInstanceType<ConstructorType extends new (...args: any[]) => any> =
  ConstructorType extends new (...args: any) => infer InstanceType ? InstanceType : any;

// 同样，在ts内置类型中，也实现了，叫：InstanceType

type res = GetInstanceType<PersonConstructor>;

// ---------------------------------------------

// 返回构造器的参数类型

type GetConstructorParameters<T extends new (...args: any[]) => any> = T extends new (
  ...args: infer P
) => any
  ? P
  : never;

type res2 = GetConstructorParameters<PersonConstructor>;

function fn1(...args: any) {}

fn1(1, 2, 3, 4, 'b', null, {}, []);

function fn2(...args: any[]) {}

fn2(1, 2, 3, 4, 'b', null, {}, []);

/**
 * 疑问点？
 *
 * 请教下作者，为什么在ts内置类型中，在限制泛型类型时，如：ThisParameterType，使用 any[] 来定义 ...args 参数，而到了ConstructorParameters中，new (...args: any) => any，...args 又使用了any来定义，这两种定义类型的方式有明确的说明，或者哪种更好吗？在尝试使用中，发现他俩基本一致，不会报什么错误
 */

// ---------------------------------------------

type GetRefProps<Props> = 'ref' extends keyof Props
  ? Props extends {
      ref?: infer Value | undefined;
    }
    ? Value
    : never
  : never;

interface Props {
  name: string;
  ref?: {
    current: null;
  };
}

type res3 = GetRefProps<Props>;

export {};
